home *** CD-ROM | disk | FTP | other *** search
/ Space & Astronomy / Space and Astronomy (October 1993).iso / mac / VIEWERS / X11 / XLOADIMG.TAR / xloadimage.c < prev    next >
C/C++ Source or Header  |  1991-05-20  |  17KB  |  700 lines

  1. /* xloadimage.c:
  2.  *
  3.  * generic image loader for X11
  4.  *
  5.  * jim frost 09.27.89
  6.  *
  7.  * Copyright 1989, 1990, 1991 Jim Frost.
  8.  * See included file "copyright.h" for complete copyright information.
  9.  */
  10.  
  11. #include "copyright.h"
  12. #include "xloadimage.h"
  13. #include "patchlevel"
  14. #include <signal.h>
  15.  
  16. extern double atof();
  17. extern int _Xdebug;
  18.  
  19. /* if an image loader needs to have our display and screen, it will get
  20.  * them from here.  this is done to keep most of the image routines
  21.  * clean
  22.  */
  23.  
  24. Display      *Disp= NULL;
  25. int           Scrn= 0;
  26.  
  27. /* used for the -default option.  this is the root weave bitmap with
  28.  * the bits in the order that xloadimage likes.
  29.  */
  30.  
  31. #define root_weave_width 4
  32. #define root_weave_height 4
  33. static byte root_weave_bits[] = {
  34.   0xe0, 0xb0, 0xd0, 0x70
  35. };
  36.  
  37. /* the real thing
  38.  */
  39.  
  40. main(argc, argv)
  41.      int argc;
  42.      char *argv[];
  43. { char         *border;
  44.   char         *dname;
  45.   Image        *dispimage;      /* image that will be sent to the display */
  46.   Image        *newimage;       /* new image we're loading */
  47.   Image        *tmpimage;
  48.   Display      *disp;           /* display we're sending to */
  49.   int           scrn;           /* screen we're sending to */
  50.   XColor        xcolor;         /* color for border option */
  51.   ImageOptions  images[MAXIMAGES + 1]; /* list of image w/ options to load */
  52.   int           a;
  53.   unsigned int  imagecount;     /* number of images in ImageName array */
  54.   char         *user_geometry;    /* -geometry passed by user */
  55.   unsigned int  dest_window;    /* window id to put image onto */
  56.   unsigned int  do_fork;
  57.   unsigned int  fit;
  58.   unsigned int  fullscreen;
  59.   unsigned int  identify;
  60.   unsigned int  install;
  61.   unsigned int  onroot;
  62.   unsigned int  private_cmap;
  63.   unsigned int  set_default;
  64.   unsigned int  use_pixmap;
  65.   unsigned int  verbose;
  66.   int           visual_class;    /* user-defined visual class */
  67.   unsigned int  winwidth, winheight; /* geometry of image */
  68.   unsigned int  global_bright= 0; /* options which are propagated to all */
  69.   unsigned int  global_colors= 0; /* remaining images */
  70.   unsigned int  global_delay= 0;
  71.   unsigned int  global_dither= 0;
  72.   float         global_gamma= 1.0;
  73.   unsigned int  global_normalize= 0;
  74.   unsigned int  global_smooth= 0;
  75.   unsigned int  global_xzoom= 0;
  76.   unsigned int  global_yzoom= 0;
  77.  
  78.   /* set up internal error handlers
  79.    */
  80.  
  81.   signal(SIGSEGV, internalError);
  82.   signal(SIGBUS, internalError);
  83.   signal(SIGFPE, internalError);
  84.   signal(SIGILL, internalError);
  85. #if defined(_AIX) && defined(_IBMR2)
  86.   /* the RS/6000 (AIX 3.1) has a new signal, SIGDANGER, which you get
  87.    * when memory is exhausted.  since malloc() can overcommit, it's a good
  88.    * idea to trap this one.
  89.    */
  90.   signal(SIGDANGER, memoryExhausted);
  91. #endif
  92.  
  93.   if (argc < 2)
  94.     usage(argv[0]);
  95.  
  96.   /* defaults and other initial settings.  some of these depend on what
  97.    * our name was when invoked.
  98.    */
  99.  
  100.   loadPathsAndExts();
  101.   onroot= 0;
  102.   verbose= 1;
  103.   if (!strcmp(tail(argv[0]), "xview")) {
  104.     onroot= 0;
  105.     verbose= 1;
  106.   }
  107.   else if (!strcmp(tail(argv[0]), "xsetbg")) {
  108.     onroot= 1;
  109.     verbose= 0;
  110.   }
  111.   border= NULL;
  112.   dname= NULL;
  113.   fit= 0;
  114.   fullscreen= 0;
  115.   do_fork= 0;
  116.   identify= 0;
  117.   install= 0;
  118.   private_cmap= 0;
  119.   use_pixmap= 0;
  120.   set_default= 0;
  121.   dest_window= 0;
  122.   user_geometry = NULL;
  123.   winwidth= winheight= 0;
  124.   visual_class= -1;
  125.  
  126.   imagecount= 0;
  127.   for (a= 0; a < MAXIMAGES; a++) {
  128.     images[a].name= NULL;
  129.     images[a].atx= images[a].aty= 0;
  130.     images[a].bright= 0;
  131.     images[a].center= 0;
  132.     images[a].clipx= images[a].clipy= 0;
  133.     images[a].clipw= images[a].cliph= 0;
  134.     images[a].colors= 0;
  135.     images[a].delay= 0;
  136.     images[a].dither= 0;
  137.     images[a].gamma= 1.0;
  138.     images[a].go_to= NULL;
  139.     images[a].gray= 0;
  140.     images[a].merge= 0;
  141.     images[a].normalize= 0;
  142.     images[a].rotate= 0;
  143.     images[a].smooth= 0;
  144.     images[a].xzoom= images[a].yzoom= 0;
  145.     images[a].fg= images[a].bg= NULL;
  146.   }
  147.   for (a= 1; a < argc; a++) {
  148.     switch (optionNumber(argv[a])) {
  149.     case OPT_BADOPT:
  150.       printf("%s: Bad option\n", argv[a]);
  151.       usage(argv[0]);
  152.       /* NOTREACHED */
  153.  
  154.     case OPT_NOTOPT:
  155.       if (imagecount == MAXIMAGES)
  156.     printf("%s: Too many images (ignoring)\n", argv[++a]);
  157.       else {
  158.     images[imagecount++].name= argv[a];
  159.     if (imagecount < MAXIMAGES) {
  160.       images[imagecount].bright= global_bright;
  161.       images[imagecount].colors= global_colors;
  162.       images[imagecount].delay= global_delay;
  163.       images[imagecount].dither= global_dither;
  164.       images[imagecount].gamma= global_gamma;
  165.       images[imagecount].normalize= global_normalize;
  166.       images[imagecount].smooth= global_smooth;
  167.       images[imagecount].xzoom= global_xzoom;
  168.       images[imagecount].yzoom= global_yzoom;
  169.     }
  170.       }
  171.       break;
  172.  
  173.     case OPT_SHORTOPT:
  174.       printf("%s: Not enough characters to identify option\n", argv[a]);
  175.       usage(argv[0]);
  176.       /* NOTREACHED */
  177.  
  178.     /* process options global to everything
  179.      */
  180.  
  181.     case ONROOT:
  182.       onroot= 1;
  183.       fit= 1; /* assume -fit */
  184.       break;
  185.  
  186.     case BORDER:
  187.       if (argv[++a])
  188.     border= argv[a];
  189.       break;
  190.  
  191.     case DBUG:
  192.       _Xdebug= True;
  193.       break;
  194.  
  195.     case DEFAULT:
  196.       set_default= 1;
  197.       break;
  198.  
  199.     case DELAY:
  200.       if (!argv[++a])
  201.       break;
  202.       global_delay= atoi(argv[a]);
  203.       if (global_delay <= 0) {
  204.       global_delay= 0;
  205.       printf("Bad argument to -delay\n");
  206.       break;
  207.       }
  208.       images[imagecount].delay= global_delay;
  209.       break;
  210.  
  211.     case DISPLAY:
  212.       if (argv[++a])
  213.     dname= argv[a];
  214.       break;
  215.  
  216.     case FIT:
  217.       fit= 1;
  218.       break;
  219.  
  220.     case FORK:
  221.       do_fork= 1;
  222.       verbose= 0; /* background processes should be seen but not heard */
  223.       break;
  224.  
  225.     case FULLSCREEN:
  226.       fullscreen= 1;
  227.       break;
  228.  
  229.     case GEOMETRY:
  230.       if (argv[++a])
  231.     user_geometry = argv[a];
  232.       break;
  233.  
  234.     case HELP:
  235.       if (argv[++a])
  236.     do {
  237.       help(argv[a++]);
  238.     } while (argv[a]); 
  239.       else
  240.     help(NULL);
  241.       exit(0);
  242.  
  243.     case IDENTIFY:
  244.       identify= 1;
  245.       break;
  246.  
  247.     case LIST:
  248.       listImages();
  249.       exit(0);
  250.  
  251.     case INSTALL:
  252.       install= 1;
  253.       break;
  254.  
  255.     case PATH:
  256.       showPath();
  257.       break;
  258.  
  259.     case PIXMAP:
  260.       use_pixmap= 1;
  261.       break;
  262.  
  263.     case PRIVATE:
  264.       private_cmap= 1;
  265.       break;
  266.  
  267.     case QUIET:
  268.       verbose= 0;
  269.       break;
  270.  
  271.     case SUPPORTED:
  272.       supportedImageTypes();
  273.       break;
  274.  
  275.     case VERBOSE:
  276.       verbose= 1;
  277.       break;
  278.  
  279.     case VER_NUM:
  280.       version();
  281.       break;
  282.  
  283.     case VIEW:
  284.       onroot= 0;
  285.       break;
  286.  
  287.     case VISUAL:
  288.       if (argv[++a])
  289.     visual_class= visualClassFromName(argv[a]);
  290.       break;
  291.  
  292.     case WINDOWID:
  293.       if (!argv[++a])
  294.     break;
  295.       if (sscanf(argv[a], "0x%x", &dest_window) != 1) {
  296.     printf("Bad argument to -windowid\n");
  297.     usage(argv[0]);
  298.     /* NOTREACHED */
  299.       }
  300.       onroot= 1; /* this means "on special root" */
  301.       fit= 1; /* assume -fit */
  302.       break;
  303.  
  304.     /* process options local to an image
  305.      */
  306.  
  307.     case AT:
  308.       if (!argv[++a])
  309.     break;
  310.       if (sscanf(argv[a], "%d,%d",
  311.          &images[imagecount].atx, &images[imagecount].aty) != 2) {
  312.     printf("Bad argument to -at\n");
  313.     usage(argv[0]);
  314.     /* NOTREACHED */
  315.       }
  316.       break;
  317.  
  318.     case BACKGROUND:
  319.       if (argv[++a])
  320.     images[imagecount].bg= argv[a];
  321.       break;
  322.  
  323.     case BRIGHT:
  324.       if (argv[++a]) {
  325.     images[imagecount].bright= atoi(argv[a]);
  326.     global_bright= images[imagecount].bright;
  327.       }
  328.       break;
  329.  
  330.     case GAMMA:
  331.       if (argv[++a]) {
  332.     images[imagecount].gamma= atof(argv[a]);
  333.     global_gamma= images[imagecount].gamma;
  334.       }
  335.       break;
  336.  
  337.     case GOTO:
  338.       if (argv[++a])
  339.     images[imagecount].go_to= argv[a];
  340.       break;
  341.  
  342.     case GRAY:
  343.       images[imagecount].gray= 1;
  344.       break;
  345.  
  346.     case CENTER:
  347.       images[imagecount].center= 1;
  348.       break;
  349.  
  350.     case CLIP:
  351.       if (!argv[++a])
  352.     break;
  353.       if (sscanf(argv[a], "%d,%d,%d,%d",
  354.          &images[imagecount].clipx, &images[imagecount].clipy,
  355.          &images[imagecount].clipw, &images[imagecount].cliph) != 4) {
  356.     printf("Bad argument to -clip\n");
  357.     usage(argv[0]);
  358.     /* NOTREACHED */
  359.       }
  360.       break;
  361.  
  362.     case COLORS:
  363.       if (!argv[++a])
  364.     break;
  365.       images[imagecount].colors= atoi(argv[a]);
  366.       if (images[imagecount].colors < 2) {
  367.     printf("Argument to -colors is too low (ignored)\n");
  368.     images[imagecount].colors= 0;
  369.       }
  370.       else if (images[imagecount].colors > 65536) {
  371.     printf("Argument to -colors is too high (ignored)\n");
  372.     images[imagecount].colors= 0;
  373.       }
  374.       global_colors= images[imagecount].colors;
  375.       break;
  376.  
  377.     case DITHER:
  378.       images[imagecount].dither= 1;
  379.       global_dither= 1;
  380.       break;
  381.  
  382.     case FOREGROUND:
  383.       if (argv[++a])
  384.     images[imagecount].fg= argv[a];
  385.       break;
  386.  
  387.     case HALFTONE:
  388.       images[imagecount].dither= 2;
  389.       global_dither= 2;
  390.       break;
  391.  
  392.     case IDELAY:
  393.       if (!argv[++a])
  394.     break;
  395.       images[a].delay= atoi(argv[a]);
  396.       if (images[a].delay <= 0) {
  397.     printf("Bad argument to -idelay\n");
  398.     images[a].delay= 0;
  399.       }
  400.       break;
  401.  
  402.     case INVERT:
  403.       images[imagecount].fg= "white";
  404.       images[imagecount].bg= "black";
  405.       break;
  406.  
  407.     case MERGE:
  408.       images[imagecount].merge= 1;
  409.       break;
  410.  
  411.     case NAME:
  412.       if (imagecount == MAXIMAGES)
  413.     printf("%s: Too many images (ignoring)\n", argv[++a]);
  414.       else
  415.     images[imagecount++].name= argv[++a];
  416.       break;
  417.  
  418.     case NEWOPTIONS:
  419.       global_bright= 0;
  420.       global_colors= 0;
  421.       global_delay= 0;
  422.       global_dither= 0;
  423.       global_gamma= 1.0;
  424.       global_normalize= 0;
  425.       global_smooth= 0;
  426.       global_xzoom= 0;
  427.       global_yzoom= 0;
  428.       break;
  429.  
  430.     case NORMALIZE:
  431.       images[imagecount].normalize= 1;
  432.       global_normalize= images[imagecount].normalize;
  433.       break;
  434.  
  435.     case ROTATE:
  436.       if (!argv[++a])
  437.     break;
  438.       images[imagecount].rotate = atoi(argv[a]);
  439.       if ((images[imagecount].rotate % 90) != 0)
  440.     { printf("Argument to -rotate must be a multiple of 90 (ignored)\n");
  441.       images[imagecount].rotate = 0;
  442.     }
  443.       else 
  444.     while (images[imagecount].rotate < 0)
  445.       images[imagecount].rotate += 360;
  446.       break;
  447.  
  448.     case SMOOTH:
  449.       global_smooth++;
  450.       images[imagecount].smooth= global_smooth;
  451.       break;
  452.  
  453.     case XZOOM:
  454.       if (argv[++a]) {
  455.     if (atoi(argv[a]) < 0) {
  456.       printf("Zoom argument must be positive (ignored).\n");
  457.       continue;
  458.     }
  459.     images[imagecount].xzoom= atoi(argv[a]);
  460.     global_xzoom= images[imagecount].xzoom;
  461.       }
  462.       break;
  463.  
  464.     case YZOOM:
  465.       if (argv[++a]) {
  466.     if (atoi(argv[a]) < 0) {
  467.       printf("Zoom argument must be positive (ignored).\n");
  468.       continue;
  469.     }
  470.     images[imagecount].yzoom= atoi(argv[a]);
  471.     global_yzoom= images[imagecount].yzoom;
  472.       }
  473.       break;
  474.  
  475.     case ZOOM:
  476.       if (argv[++a]) {
  477.     if (atoi(argv[a]) < 0) {
  478.       printf("Zoom argument must be positive (ignored).\n");
  479.       continue;
  480.     }
  481.     images[imagecount].xzoom= images[imagecount].yzoom= atoi(argv[a]);
  482.     global_xzoom= global_yzoom= images[imagecount].xzoom;
  483.       }
  484.       break;
  485.  
  486.     default:
  487.  
  488.       /* this should not happen!
  489.        */
  490.  
  491.       printf("%s: Internal error parsing arguments\n", argv[0]);
  492.       exit(1);
  493.     }
  494.   }
  495.  
  496.   if (fit && (visual_class != -1)) {
  497.     printf("-fit and -visual options are mutually exclusive (ignoring -visual)\n");
  498.     visual_class= -1;
  499.   }
  500.  
  501.   if (!imagecount && !set_default) /* NO-OP from here on */
  502.     exit(0);
  503.  
  504.   if (identify) {                    /* identify the named image(s) */
  505.     for (a= 0; a < imagecount; a++)
  506.       identifyImage(images[a].name);
  507.     exit(0);
  508.   }
  509.  
  510.   /* start talking to the display
  511.    */
  512.  
  513.   if (! (Disp= disp= XOpenDisplay(dname))) {
  514.     printf("%s: Cannot open display\n", XDisplayName(dname));
  515.     exit(1);
  516.   }
  517.   Scrn= scrn= DefaultScreen(disp);
  518.   XSetErrorHandler(errorHandler);
  519.  
  520.   /* background ourselves if the user asked us to
  521.    */
  522.  
  523.   if (do_fork)
  524.     switch(fork()) {
  525.     case -1:
  526.       perror("fork");
  527.       /* FALLTHRU */
  528.     case 0:
  529.       break;
  530.     default:
  531.       exit(0);
  532.     }
  533.  
  534.   /* handle -default option.  this resets the colormap and loads the
  535.    * default root weave.
  536.    */
  537.  
  538.   if (set_default) {
  539.     byte *old_data;
  540.  
  541.     dispimage= newBitImage(root_weave_width, root_weave_height);
  542.     old_data= dispimage->data;
  543.     dispimage->data= root_weave_bits;
  544.     imageOnRoot(disp, scrn, dest_window, dispimage, 0);
  545.     dispimage->data= old_data;
  546.     freeImage(dispimage);
  547.     if (!imagecount) /* all done */
  548.       exit(0);
  549.   }
  550.  
  551.   dispimage= NULL;
  552.  
  553.   if (onroot && (winwidth || winheight || images[0].center ||
  554.       images[0].atx || images[0].aty || fullscreen)) {
  555.     if (!winwidth)
  556.     winwidth= DisplayWidth(disp, scrn);
  557.     if (!winheight)
  558.       winheight= DisplayHeight(disp, scrn);
  559.     if (DefaultDepth(disp, scrn) == 1)
  560.       dispimage= newBitImage(winwidth, winheight);
  561.     else {
  562.       dispimage= newRGBImage(winwidth, winheight, DefaultDepth(disp, scrn));
  563.       dispimage->rgb.used= 1;
  564.     }
  565.     *(dispimage->rgb.red)= 65535;   /* default border value is white */
  566.     *(dispimage->rgb.green)= 65535;
  567.     *(dispimage->rgb.blue)= 65535;
  568.     if (border) {
  569.       XParseColor(disp, DefaultColormap(disp, scrn), border, &xcolor);
  570.       *dispimage->rgb.red= xcolor.red;
  571.       *dispimage->rgb.green= xcolor.green;
  572.       *dispimage->rgb.blue= xcolor.blue;
  573.     }
  574.  
  575.     /* bitmap needs both black and white
  576.      */
  577.  
  578.     if (DefaultDepth(disp, scrn) == 1) {
  579.     if (*(dispimage->rgb.red)) {
  580.         *(dispimage->rgb.red + 1)= 0;
  581.         *(dispimage->rgb.green + 1)= 0;
  582.         *(dispimage->rgb.blue + 1)= 0;
  583.     }
  584.     else {
  585.         *(dispimage->rgb.red + 1)= 65535;
  586.         *(dispimage->rgb.green + 1)= 65535;
  587.         *(dispimage->rgb.blue + 1)= 65535;
  588.     }
  589.     }
  590.     fill(dispimage, 0, 0, winwidth, winheight, 0);
  591.   }
  592.  
  593.   /* load in each named image
  594.    */
  595.  
  596.   for (a= 0; a < imagecount; a++) {
  597.     if (! (newimage= loadImage(images[a].name, verbose)))
  598.       continue;
  599.     if (!images[a].dither &&
  600.     ((dispimage && BITMAPP(dispimage)) || (DefaultDepth(disp, scrn) == 1)))
  601.       images[a].dither= 1;
  602.  
  603.     /* if this is the first image and we're putting it on the root window
  604.      * in fullscreen mode, set the zoom factors and
  605.      * location to something reasonable.
  606.      */
  607.  
  608.     if ((a == 0) && onroot && fullscreen &&
  609.     (images[0].xzoom == 0.0) && (images[0].yzoom == 0.0) &&
  610.     (images[0].atx == 0) && (images[0].aty == 0) &&
  611.     (images[0].center == 0)) {
  612.       XWindowAttributes wa;
  613.       images[0].center= 1;
  614.     
  615.       if ((newimage->width > DisplayWidth(disp, scrn)) ||
  616.       (newimage->height > DisplayHeight(disp, scrn))) {
  617.     images[0].xzoom= images[0].yzoom=
  618.       (newimage->width - DisplayWidth(disp, scrn) >
  619.        newimage->height - DisplayHeight(disp, scrn) ?
  620.        (float)DisplayWidth(disp, scrn) / (float)newimage->width * 100.0 :
  621.        (float)DisplayHeight(disp, scrn) / (float)newimage->height * 100.0);
  622.       }
  623.       else {
  624.     images[0].xzoom= images[0].yzoom=
  625.       (DisplayWidth(disp, scrn) - newimage->width <
  626.        DisplayHeight(disp, scrn) - newimage->height ?
  627.        (float)DisplayWidth(disp, scrn) / (float)newimage->width * 100.0 :
  628.        (float)DisplayHeight(disp, scrn) / (float)newimage->height * 100.0);
  629.       }
  630.     }
  631.  
  632.     newimage= processImage(disp, scrn, newimage, &images[a], verbose);
  633.  
  634.     if (images[a].center && dispimage) {
  635.       images[a].atx= (int)(dispimage->width - newimage->width) / 2;
  636.       images[a].aty= (int)(dispimage->height - newimage->height) / 2;
  637.     }
  638.     if (dispimage) {
  639.       if (! dispimage->title)
  640.     dispimage->title= dupString(newimage->title);
  641.       tmpimage= merge(dispimage, newimage, images[a].atx, images[a].aty,
  642.               verbose);
  643.       if (dispimage != tmpimage) {
  644.     freeImage(dispimage);
  645.     dispimage= tmpimage;
  646.       }
  647.       freeImage(newimage);
  648.     }
  649.     else
  650.       dispimage= newimage;
  651.  
  652.     /* if next image is to be merged onto this one, do it now
  653.      */
  654.  
  655.     if (onroot || ((a < imagecount) && (images[a + 1].merge)))
  656.       continue;
  657.  
  658.     switch(imageInWindow(disp, scrn, dispimage, user_geometry,
  659.              fullscreen, install, private_cmap, fit, use_pixmap,
  660.              images[a].delay, visual_class, argc, argv, verbose)) {
  661.     case '\0': /* window got nuked by someone */
  662.       XCloseDisplay(disp);
  663.       exit(1);
  664.     case '\003':
  665.     case 'q':  /* user quit */
  666.       cleanUpWindow(disp);
  667.       XCloseDisplay(disp);
  668.       exit(0);
  669.     case ' ':
  670.     case 'n':  /* next image */
  671.       if (images[a + 1].go_to) {
  672.     int b;
  673.     for (b= 0; b < imagecount; b++)
  674.       if (!strcmp(images[b].name, images[a + 1].go_to)) {
  675.         a= b - 1;
  676.         goto next_image;
  677.       }
  678.     fprintf(stderr, "Target for -goto %s was not found\n",
  679.         images[a + 1].go_to);
  680.       next_image:
  681.     ;
  682.       }
  683.       break;
  684.     case 'p':  /* previous image */
  685.       if (a > 0)
  686.     a -= 2;
  687.       else
  688.     a--;
  689.       break;
  690.     }
  691.     freeImage(dispimage);
  692.     dispimage= NULL;
  693.   }
  694.  
  695.   if (onroot)
  696.     imageOnRoot(disp, scrn, dest_window, dispimage, verbose);
  697.   XCloseDisplay(disp);
  698.   exit(0);
  699. }
  700.